//===============================================================================
// Copyright (C) 2008 Charles River Media. All rights reserved.
// 
// Catmull-Clark subdivision surface viewer program
//
// The developer of the code is
// Gyorgy Antal <gyantal@gmail.com>
//
// Contributor(s):
// Laszlo Szirmay-Kalos <szirmay@iit.bme.hu>
//
// The software was developed for the chapter 
// "Fast Evaluation of Subdivision Surfaces on DirectX10 Graphics Hardware"
// of the book ShaderX 6: Advanced Rendering Techniques, 
// edited by Wolfgang Engel,
// the appropriate section edited by Tom Forsyth. 
//
// The files are provided without support, instruction, or implied warranty of any
// kind.  Charles River Media makes no guarantee of its fitness for a particular purpose and is
// not liable under any circumstances for any damages or loss whatsoever arising
// from the use or inability to use this file or items derived from it.
//
// The source code can be found in the RenderVista project: 
// http://code.google.com/p/rendervista/source
// More specifically on this site:
// http://rendervista.googlecode.com/svn/trunk/Projects/DX10Subdivision/
//===============================================================================
// File: GSSubdivider.cpp
//
// Description:
// The bulk of the subdivision work is performed here.
//===============================================================================

#include "DXFramework.h"
#include "..\Base\Base.h"
#include "..\Base\SceneLoader.h"


#define SCENE_EXTERN __declspec(dllimport)
#include "..\Base\scene.h"


ID3D10Effect*               g_pEffect = NULL;       // D3DX effect interface
ID3D10EffectTechnique*      g_pTechnique = NULL;
ID3D10EffectMatrixVariable* g_pWorldViewProjectionVariable = NULL;
ID3D10EffectVectorVariable* g_pvEyePt = NULL;
ID3D10InputLayout*          g_pVertexLayout = NULL; // Vertex Layout

//************************
ID3D10Buffer*						g_fakePointsVertexBuffer = NULL;

ID3D10Buffer*						g_vertPosValenceBuffer = NULL;
ID3D10ShaderResourceView*			g_vertPosValenceBufferRView = NULL;
ID3D10EffectShaderResourceVariable* g_vertPosValenceBufferRVar = NULL;

ID3D10Buffer*						g_texUvBuffer = NULL;
ID3D10ShaderResourceView*			g_texUvBufferRView = NULL;
ID3D10EffectShaderResourceVariable* g_texUvBufferRVar = NULL;

ID3D10Buffer*						g_normalBuffer = NULL;
ID3D10ShaderResourceView*			g_normalBufferRView = NULL;
ID3D10EffectShaderResourceVariable* g_normalBufferRVar = NULL;

ID3D10Buffer*						g_tangentBuffer = NULL;
ID3D10ShaderResourceView*			g_tangentBufferRView = NULL;
ID3D10EffectShaderResourceVariable* g_tangentBufferRVar = NULL;

ID3D10Buffer*						g_quadTextureIndBuffer = NULL;
ID3D10ShaderResourceView*			g_quadTextureIndBufferRView = NULL;
ID3D10EffectShaderResourceVariable* g_quadTextureIndBufferRVar = NULL;

ID3D10Buffer*						g_quadNormalIndBuffer = NULL;
ID3D10ShaderResourceView*			g_quadNormalIndBufferRView = NULL;
ID3D10EffectShaderResourceVariable* g_quadNormalIndBufferRVar = NULL;

ID3D10Buffer*						g_quadTangentIndBuffer = NULL;
ID3D10ShaderResourceView*			g_quadTangentIndBufferRView = NULL;
ID3D10EffectShaderResourceVariable* g_quadTangentIndBufferRVar = NULL;

ID3D10Buffer*						g_quadAndAdjacentVerticesBuffer = NULL;
ID3D10ShaderResourceView*			g_quadAndAdjacentVerticesBufferRView = NULL;
ID3D10EffectShaderResourceVariable* g_quadAndAdjacentVerticesBufferRVar = NULL;

ID3D10ShaderResourceView*			g_diffuseTextureRView = NULL;
ID3D10EffectShaderResourceVariable* g_diffuseTextureRVar = NULL;

ID3D10ShaderResourceView*			g_normalMapTextureRView = NULL;
ID3D10EffectShaderResourceVariable* g_normalMapTextureRVar = NULL;


HRESULT  CreateVertPosValenceBuffer(ID3D10Device* pd3dDevice)
{
	HRESULT hr;

	D3DXVECTOR4 vertPos[MaxVertCount];
	for (int i = 0; i < g_nVerts; i++)
	{
		vertPos[i].x = g_vertices[i].Pos.x;
		vertPos[i].y = g_vertices[i].Pos.y;
		vertPos[i].z = g_vertices[i].Pos.z;
		vertPos[i].w = (float)(g_vertValences[i]);
		//unsigned int valence = g_vertValences[i];
		//vertPos[i].w = *((float*)(&valence));
	}

	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(D3DXVECTOR4) * g_nVerts;
	bd.BindFlags = D3D10_BIND_SHADER_RESOURCE;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA InitData;
	InitData.pSysMem = vertPos;
	hr = pd3dDevice->CreateBuffer(&bd, &InitData, &g_vertPosValenceBuffer);

	// Create the shader-resource view
	D3D10_SHADER_RESOURCE_VIEW_DESC srDesc;
	srDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
	srDesc.ViewDimension = D3D10_SRV_DIMENSION_BUFFER;
	srDesc.Buffer.ElementOffset = 0;
	srDesc.Buffer.ElementWidth = g_nVerts;
	pd3dDevice->CreateShaderResourceView(g_vertPosValenceBuffer, &srDesc, &g_vertPosValenceBufferRView);

	return S_OK;
}

HRESULT  CreateTexUvBuffer(ID3D10Device* pd3dDevice)
{
	HRESULT hr;

	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(D3DXVECTOR2) * g_nTextureUvs;
	bd.BindFlags = D3D10_BIND_SHADER_RESOURCE;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA InitData;
	InitData.pSysMem = g_textureUvs;
	hr = pd3dDevice->CreateBuffer(&bd, &InitData, &g_texUvBuffer);

	// Create the shader-resource view
	D3D10_SHADER_RESOURCE_VIEW_DESC srDesc;
	srDesc.Format = DXGI_FORMAT_R32G32_FLOAT;
	srDesc.ViewDimension = D3D10_SRV_DIMENSION_BUFFER;
	srDesc.Buffer.ElementOffset = 0;
	srDesc.Buffer.ElementWidth = g_nTextureUvs;
	pd3dDevice->CreateShaderResourceView(g_texUvBuffer, &srDesc, &g_texUvBufferRView);

	return S_OK;
}


HRESULT  CreateNormalBuffer(ID3D10Device* pd3dDevice)
{
	HRESULT hr;

	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(D3DXVECTOR3) * g_nNormals;
	bd.BindFlags = D3D10_BIND_SHADER_RESOURCE;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA InitData;
	InitData.pSysMem = g_normals;
	hr = pd3dDevice->CreateBuffer(&bd, &InitData, &g_normalBuffer);

	// Create the shader-resource view
	D3D10_SHADER_RESOURCE_VIEW_DESC srDesc;
	srDesc.Format = DXGI_FORMAT_R32G32B32_FLOAT;
	srDesc.ViewDimension = D3D10_SRV_DIMENSION_BUFFER;
	srDesc.Buffer.ElementOffset = 0;
	srDesc.Buffer.ElementWidth = g_nNormals;
	pd3dDevice->CreateShaderResourceView(g_normalBuffer, &srDesc, &g_normalBufferRView);

	return S_OK;
}


HRESULT  CreateTangentBuffer(ID3D10Device* pd3dDevice)
{
	HRESULT hr;

	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(D3DXVECTOR3) * g_nTangents;
	bd.BindFlags = D3D10_BIND_SHADER_RESOURCE;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA InitData;
	InitData.pSysMem = g_tangents;
	hr = pd3dDevice->CreateBuffer(&bd, &InitData, &g_tangentBuffer);

	// Create the shader-resource view
	D3D10_SHADER_RESOURCE_VIEW_DESC srDesc;
	srDesc.Format = DXGI_FORMAT_R32G32B32_FLOAT;
	srDesc.ViewDimension = D3D10_SRV_DIMENSION_BUFFER;
	srDesc.Buffer.ElementOffset = 0;
	srDesc.Buffer.ElementWidth = g_nTangents;
	pd3dDevice->CreateShaderResourceView(g_tangentBuffer, &srDesc, &g_tangentBufferRView);

	return S_OK;
}


int quadAndAdjacentVerticesInd[24 * MaxQuadCount];
HRESULT  CreateQuadAndAdjacencyBuffer(ID3D10Device* pd3dDevice)
{
	HRESULT hr;

	for	(int i= 0; i < g_nQuads; i++)
	{
		quadAndAdjacentVerticesInd[i * 24] = g_quads[i].VertIndex0;
		quadAndAdjacentVerticesInd[i * 24 + 1] = g_quads[i].VertIndex1;
		quadAndAdjacentVerticesInd[i * 24 + 2] = g_quads[i].VertIndex2;
		quadAndAdjacentVerticesInd[i * 24 + 3] = g_quads[i].VertIndex3;

		quadAndAdjacentVerticesInd[i * 24 + 4] = g_quadAdjacentVerticesInd[i * 20];
		quadAndAdjacentVerticesInd[i * 24 + 5] = g_quadAdjacentVerticesInd[i * 20 + 1];
		quadAndAdjacentVerticesInd[i * 24 + 6] = g_quadAdjacentVerticesInd[i * 20 + 2];
		quadAndAdjacentVerticesInd[i * 24 + 7] = g_quadAdjacentVerticesInd[i * 20 + 3];
		quadAndAdjacentVerticesInd[i * 24 + 8] = g_quadAdjacentVerticesInd[i * 20 + 4];
		quadAndAdjacentVerticesInd[i * 24 + 9] = g_quadAdjacentVerticesInd[i * 20 + 5];
		quadAndAdjacentVerticesInd[i * 24 + 10] = g_quadAdjacentVerticesInd[i * 20 + 6];
		quadAndAdjacentVerticesInd[i * 24 + 11] = g_quadAdjacentVerticesInd[i * 20 + 7];
		quadAndAdjacentVerticesInd[i * 24 + 12] = g_quadAdjacentVerticesInd[i * 20 + 8];
		quadAndAdjacentVerticesInd[i * 24 + 13] = g_quadAdjacentVerticesInd[i * 20 + 9];
		quadAndAdjacentVerticesInd[i * 24 + 14] = g_quadAdjacentVerticesInd[i * 20 + 10];
		quadAndAdjacentVerticesInd[i * 24 + 15] = g_quadAdjacentVerticesInd[i * 20 + 11];
		quadAndAdjacentVerticesInd[i * 24 + 16] = g_quadAdjacentVerticesInd[i * 20 + 12];
		quadAndAdjacentVerticesInd[i * 24 + 17] = g_quadAdjacentVerticesInd[i * 20 + 13];
		quadAndAdjacentVerticesInd[i * 24 + 18] = g_quadAdjacentVerticesInd[i * 20 + 14];
		quadAndAdjacentVerticesInd[i * 24 + 19] = g_quadAdjacentVerticesInd[i * 20 + 15];
		quadAndAdjacentVerticesInd[i * 24 + 20] = g_quadAdjacentVerticesInd[i * 20 + 16];
		quadAndAdjacentVerticesInd[i * 24 + 21] = g_quadAdjacentVerticesInd[i * 20 + 17];
		quadAndAdjacentVerticesInd[i * 24 + 22] = g_quadAdjacentVerticesInd[i * 20 + 18];
		quadAndAdjacentVerticesInd[i * 24 + 23] = g_quadAdjacentVerticesInd[i * 20 + 19];
	}

	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(unsigned int) * g_nQuads * 24;
	bd.BindFlags = D3D10_BIND_SHADER_RESOURCE;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA InitData;
	InitData.pSysMem = quadAndAdjacentVerticesInd;
	hr = pd3dDevice->CreateBuffer(&bd, &InitData, &g_quadAndAdjacentVerticesBuffer);

	// Create the shader-resource view
	D3D10_SHADER_RESOURCE_VIEW_DESC srDesc;
	//srDesc.Format = DXGI_FORMAT_R32_UINT;
	srDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT;
	srDesc.ViewDimension = D3D10_SRV_DIMENSION_BUFFER;
	srDesc.Buffer.ElementOffset = 0;
	//srDesc.Buffer.ElementWidth = g_nQuads * 24;
	srDesc.Buffer.ElementWidth = g_nQuads * 6;
	pd3dDevice->CreateShaderResourceView(g_quadAndAdjacentVerticesBuffer, &srDesc, &g_quadAndAdjacentVerticesBufferRView);

	return S_OK;
}

HRESULT  CreateQuadTextureIndBuffer(ID3D10Device* pd3dDevice)
{
	HRESULT hr;

	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(QuadTextureInd) * g_nQuads;
	bd.BindFlags = D3D10_BIND_SHADER_RESOURCE;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA InitData;
	InitData.pSysMem = g_quadTextureInd;
	hr = pd3dDevice->CreateBuffer(&bd, &InitData, &g_quadTextureIndBuffer);

	// Create the shader-resource view
	D3D10_SHADER_RESOURCE_VIEW_DESC srDesc;
	srDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT;
	srDesc.ViewDimension = D3D10_SRV_DIMENSION_BUFFER;
	srDesc.Buffer.ElementOffset = 0;
	srDesc.Buffer.ElementWidth = g_nQuads;
	pd3dDevice->CreateShaderResourceView(g_quadTextureIndBuffer, &srDesc, &g_quadTextureIndBufferRView);

	return S_OK;
}


HRESULT  CreateQuadNormalIndBuffer(ID3D10Device* pd3dDevice)
{
	HRESULT hr;

	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(QuadNormalInd) * g_nQuads;
	bd.BindFlags = D3D10_BIND_SHADER_RESOURCE;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA InitData;
	InitData.pSysMem = g_quadNormalInd;
	hr = pd3dDevice->CreateBuffer(&bd, &InitData, &g_quadNormalIndBuffer);

	// Create the shader-resource view
	D3D10_SHADER_RESOURCE_VIEW_DESC srDesc;
	srDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT;
	srDesc.ViewDimension = D3D10_SRV_DIMENSION_BUFFER;
	srDesc.Buffer.ElementOffset = 0;
	srDesc.Buffer.ElementWidth = g_nQuads;
	pd3dDevice->CreateShaderResourceView(g_quadNormalIndBuffer, &srDesc, &g_quadNormalIndBufferRView);

	return S_OK;
}

HRESULT  CreateQuadTangentIndBuffer(ID3D10Device* pd3dDevice)
{
	HRESULT hr;

	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(QuadTangentInd) * g_nQuads;
	bd.BindFlags = D3D10_BIND_SHADER_RESOURCE;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA InitData;
	InitData.pSysMem = g_quadTangentInd;
	hr = pd3dDevice->CreateBuffer(&bd, &InitData, &g_quadTangentIndBuffer);

	// Create the shader-resource view
	D3D10_SHADER_RESOURCE_VIEW_DESC srDesc;
	srDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT;
	srDesc.ViewDimension = D3D10_SRV_DIMENSION_BUFFER;
	srDesc.Buffer.ElementOffset = 0;
	srDesc.Buffer.ElementWidth = g_nQuads;
	pd3dDevice->CreateShaderResourceView(g_quadTangentIndBuffer, &srDesc, &g_quadTangentIndBufferRView);

	return S_OK;
}


HRESULT  AdjustDirectXResourcesForModel(ID3D10Device* pd3dDevice)
{
	HRESULT hr;	
	CreateVertPosValenceBuffer(pd3dDevice);
	CreateTexUvBuffer(pd3dDevice);
	CreateNormalBuffer(pd3dDevice);
	CreateTangentBuffer(pd3dDevice);

	CreateQuadAndAdjacencyBuffer(pd3dDevice);
	CreateQuadTextureIndBuffer(pd3dDevice);
	CreateQuadNormalIndBuffer(pd3dDevice);
	CreateQuadTangentIndBuffer(pd3dDevice);

	SimplePointVertex* pointVertices = new SimplePointVertex[g_nQuads];
	for (int i = 0; i < g_nQuads; i++)
	{
		pointVertices[i].Index = i;
	}

	D3D10_BUFFER_DESC bd;
	//bd.Usage = D3D10_USAGE_DEFAULT;
	//bd.Usage = D3D10_USAGE_DYNAMIC;
	bd.Usage = D3D10_USAGE_IMMUTABLE;
	bd.ByteWidth = sizeof(SimplePointVertex) * g_nQuads;
	bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	//bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
	bd.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA InitData;
	InitData.pSysMem = pointVertices;
	hr = pd3dDevice->CreateBuffer(&bd, &InitData, &g_fakePointsVertexBuffer);
	if(FAILED(hr))
		return hr;

	//UINT subResource = D3D10CalcSubresource(0, 0, 1);
	//void* ppData;
	//g_pVertexBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &ppData);

	return S_OK;
}


HRESULT BuildDxDataFromScene(ID3D10Device* pd3dDevice)
{
	AdjustDirectXResourcesForModel(pd3dDevice);

	// when compiling a shader from HLSL, the Avoid_Flow_Control means 
	// that the 'IF' and 'LOOP' instructions will be not used in the compiled assembly shader 
	// for example this is how the compiled assembly-shader looks, if Flow Control is allowed
	// if_nz r0.z
    //      add r7.yzw, r4.xxyz, r10.xxyz
	//	else 
	//		add r7.yzw, r4.xxyz, r11.xxyz
	// In contrast, if D3D10_SHADER_AVOID_FLOW_CONTROL is set, it is compiled as 3 instructions, 
	// but there will be no IF among them.
	// This is needed now, because the Nvidia driver (currently: 158.24WHQL and the 163.11Beta) has problems.
	// The Nvidia compiler cannot compile this complex shader (1200 assembly instructions), if 
	// the flow control is permitted, so we have to prohibit now (2007-07-19).
	// It can compile a less complex shader with Flow control enabled, but it runs 
	// the shader with errors. Some vertices placed in wrong positions. Not only the compiler
	// has flaws but running Geometry Shaders with flow control is buggy too.
	// Interestingly, if Flow Control is not allowed, the rendering is faster.
	// For Level1 subdivision, the speed is increased from 129fps to 236fps
	// for Level2 subdivision, the speed is approximately the same: 23fps for the enabled flow control case
	// and 25fps when flow control is disabled


	// Create the effect
	//DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
	DWORD dwShaderFlags = D3D10_SHADER_AVOID_FLOW_CONTROL;	// slower, but works with every driver not only the 163.71 driver
	//DWORD dwShaderFlags = 0;
	//DWORD dwShaderFlags = D3D10_SHADER_AVOID_FLOW_CONTROL || D3D10_SHADER_SKIP_OPTIMIZATION || D3D10_SHADER_SKIP_VALIDATION;
#if defined(DEBUG) || defined(_DEBUG)
	// Set the D3D10_SHADER_DEBUG flag to embed debug information in the shaders.
	// Setting this flag improves the shader debugging experience, but still allows 
	// the shaders to be optimized and to run exactly the way they will run in 
	// the release configuration of this program.
	//dwShaderFlags |= D3D10_SHADER_DEBUG;
#endif

	ID3D10Blob* ppErrors;
	HRESULT hr = D3DX10CreateEffectFromFile(L"Shader.fx", NULL, NULL, "fx_4_0", dwShaderFlags, 0, g_pd3dDevice, NULL, NULL, &g_pEffect, &ppErrors, NULL);
	if(FAILED(hr))
	{
		MessageBox(NULL, L"The FX file cannot be located.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK);
		return hr;
	}

	// Obtain the default technique
	g_pTechnique = g_pEffect->GetTechniqueByName("RenderLevel2");

	// Obtain the variables
	g_pWorldViewProjectionVariable = g_pEffect->GetVariableByName("g_mWorldViewProj")->AsMatrix();
	g_pvEyePt = g_pEffect->GetVariableByName("g_vEyePt")->AsVector();

	g_vertPosValenceBufferRVar = g_pEffect->GetVariableByName("g_vertPosValenceBuffer")->AsShaderResource();
	g_vertPosValenceBufferRVar->SetResource(g_vertPosValenceBufferRView);

	g_texUvBufferRVar = g_pEffect->GetVariableByName("g_texUvBuffer")->AsShaderResource();
	g_texUvBufferRVar->SetResource(g_texUvBufferRView);

	g_normalBufferRVar = g_pEffect->GetVariableByName("g_normalBuffer")->AsShaderResource();
	g_normalBufferRVar->SetResource(g_normalBufferRView);

	g_tangentBufferRVar = g_pEffect->GetVariableByName("g_tangentBuffer")->AsShaderResource();
	g_tangentBufferRVar->SetResource(g_tangentBufferRView);

	g_quadAndAdjacentVerticesBufferRVar = g_pEffect->GetVariableByName("g_quadAndAdjacentVerticesBuffer")->AsShaderResource();
	g_quadAndAdjacentVerticesBufferRVar->SetResource(g_quadAndAdjacentVerticesBufferRView);

	g_quadTextureIndBufferRVar = g_pEffect->GetVariableByName("g_quadTextureIndBuffer")->AsShaderResource();
	g_quadTextureIndBufferRVar->SetResource(g_quadTextureIndBufferRView);

	g_quadNormalIndBufferRVar = g_pEffect->GetVariableByName("g_quadNormalIndBuffer")->AsShaderResource();
	g_quadNormalIndBufferRVar->SetResource(g_quadNormalIndBufferRView);

	g_quadTangentIndBufferRVar = g_pEffect->GetVariableByName("g_quadTangentIndBuffer")->AsShaderResource();
	g_quadTangentIndBufferRVar->SetResource(g_quadTangentIndBufferRView);


	hr = D3DX10CreateShaderResourceViewFromFile(pd3dDevice, L"..\\Media\\Lizardrock_Diff2.jpg", NULL, NULL, &g_diffuseTextureRView, NULL);
	hr = D3DX10CreateShaderResourceViewFromFile(pd3dDevice, L"..\\Media\\monsterfrog-n.bmp", NULL, NULL, &g_normalMapTextureRView, NULL);


	g_diffuseTextureRVar = g_pEffect->GetVariableByName("g_texDiffuse")->AsShaderResource();
	g_diffuseTextureRVar->SetResource(g_diffuseTextureRView);

	g_normalMapTextureRVar = g_pEffect->GetVariableByName("g_texNormalMap")->AsShaderResource();
	g_normalMapTextureRVar->SetResource(g_normalMapTextureRView);

	// Define the input layout
	D3D10_INPUT_ELEMENT_DESC layout[] =
	{
		{ "POSINDEX", 0, DXGI_FORMAT_R32_UINT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },        
	};
	UINT numElements = sizeof(layout)/sizeof(layout[0]);
	// Create the input layout
	D3D10_PASS_DESC PassDesc;
	g_pTechnique->GetPassByIndex(0)->GetDesc(&PassDesc);
	hr = pd3dDevice->CreateInputLayout(layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pVertexLayout);
	if(FAILED(hr))
		return hr;
	// Set the input layout
	pd3dDevice->IASetInputLayout(g_pVertexLayout);
	return S_OK;
}


void InitRenderSubdiv(ID3D10Device* pd3dDevice, int p_width, int p_height)
{
	D3DXMATRIX world;
	D3DXMATRIX view;
	D3DXMATRIX projection;
	// Initialize the world matrices
	D3DXMatrixIdentity(&world);

	// Initialize the view matrix
	//D3DXVECTOR3 Eye(1.0f, 1.0f, -2.0f);		// for the cube
	//D3DXVECTOR3 Eye(-35.0f, 23.0f, -27.0f);		// for the lizard, original position
	//D3DXVECTOR3 Eye(-55.0f, 13.0f, -27.0f);		// for the lizard, original position, original side
	//D3DXVECTOR3 Eye(57.0f, 0.0f, -25.0f);		// for the lizard, the other side
	
	D3DXVECTOR3 Eye(-55.0f, 13.0f, -27.0f);	

	D3DXVECTOR3 At(0.0f, 0.0f, 0.0f);

	D3DXVECTOR3 Up(0.0f, 1.0f, 0.0f);
	D3DXMatrixLookAtLH(&view, &Eye, &At, &Up);	// left-handed, look-at matrix.

	// Initialize the projection matrix
	D3DXMatrixPerspectiveFovLH(&projection, (float)D3DX_PI * 0.25f, p_width/(FLOAT)p_height, 0.1f, 100.0f);
	D3DXMATRIX worldViewProjection = world * view * projection;
	g_pWorldViewProjectionVariable->SetMatrix((float*)&worldViewProjection);
	g_pvEyePt->SetFloatVector((float*)&Eye);

	//// Set the input layout
	//pd3dDevice->IASetInputLayout(g_pVertexLayout);
	//// Set primitive topology
	//pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_POINTLIST);
}

HRESULT  InitAfterDeviceCreation(int p_width, int p_height)
{
	LoadModelData_OBJ("..\\Media\\monsterfrog_mapped_00_5.obj");
	//LoadModelData_OBJ("..\\Media\\SimpleCubeRightHandledSystem2.obj");		// this is the cube for testing with good UV-s
	BuildDxDataFromScene(g_pd3dDevice);
	InitRenderSubdiv(g_pd3dDevice, p_width, p_height);
	return S_OK;
}


void ChangeSubdivLevel(unsigned int p_level)
{
	if (p_level == 0)
		g_pTechnique = g_pEffect->GetTechniqueByName("RenderLevel0");
	else if (p_level == 1)
		g_pTechnique = g_pEffect->GetTechniqueByName("RenderLevel1");
	else 
		g_pTechnique = g_pEffect->GetTechniqueByName("RenderLevel2");
}


void RenderSubdiv(ID3D10Device* pd3dDevice)
{
	// we need to Set many things, since font.DrawText() will overwrite the IASetVertexBuffers, IASetInputLayout, IASetPrimitiveTopology
	// Set the input layout
	pd3dDevice->IASetInputLayout(g_pVertexLayout);
	// Set primitive topology
	pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_POINTLIST);

	// Set vertex buffer
	UINT stride = sizeof(SimplePointVertex);
	UINT offset = 0;
	pd3dDevice->IASetVertexBuffers(0, 1, &g_fakePointsVertexBuffer, &stride, &offset);

	// Renders the fake pointList
	D3D10_TECHNIQUE_DESC techDesc;
	g_pTechnique->GetDesc(&techDesc);
	for(UINT p = 0; p < techDesc.Passes; ++p)
	{
		g_pTechnique->GetPassByIndex(p)->Apply(0);
		pd3dDevice->Draw(g_nQuads, 0);        // render g_nQuads points
	}
}



void  CleanupBeforFreeDevice()
{
	SAFE_RELEASE(g_fakePointsVertexBuffer);
	SAFE_RELEASE(g_pVertexLayout);
	SAFE_RELEASE(g_pEffect);

	SAFE_RELEASE(g_vertPosValenceBuffer);
	SAFE_RELEASE(g_vertPosValenceBufferRView);

	SAFE_RELEASE(g_texUvBuffer);
	SAFE_RELEASE(g_texUvBufferRView);

	SAFE_RELEASE(g_normalBuffer);
	SAFE_RELEASE(g_normalBufferRView);

	SAFE_RELEASE(g_tangentBuffer);
	SAFE_RELEASE(g_tangentBufferRView);

	SAFE_RELEASE(g_quadTextureIndBuffer);
	SAFE_RELEASE(g_quadTextureIndBufferRView);

	SAFE_RELEASE(g_quadNormalIndBuffer);
	SAFE_RELEASE(g_quadNormalIndBufferRView);

	SAFE_RELEASE(g_quadTangentIndBuffer);
	SAFE_RELEASE(g_quadTangentIndBufferRView);	

	SAFE_RELEASE(g_quadAndAdjacentVerticesBuffer);
	SAFE_RELEASE(g_quadAndAdjacentVerticesBufferRView);

	if (g_diffuseTextureRView != NULL)
	{
		ID3D10Resource* resource;
		g_diffuseTextureRView->GetResource(&resource);
		resource->Release();

	}
	SAFE_RELEASE(g_diffuseTextureRView);

	if (g_normalMapTextureRView != NULL)
	{
		ID3D10Resource* resource;
		g_normalMapTextureRView->GetResource(&resource);
		resource->Release();

	}
	SAFE_RELEASE(g_normalMapTextureRView);
}
